/**
 * @description: JWT验证并增加参数
 * @version: 0.0.1
 * @author: xiech
 * @Date: 2023-06-01 14:10:24
 */

import { Config, Inject, Middleware } from '@midwayjs/decorator';
import { Context, NextFunction } from '@midwayjs/koa';
import { httpError, RouterInfo, MidwayWebRouterService } from '@midwayjs/core';
import { UserService } from "../service/user.service"

/**
 * 权限校验
 */
@Middleware()
export class AuthMiddleware {
  @Inject()
  webRouterService: MidwayWebRouterService;

  @Inject()
  notAuthRouters: RouterInfo[];

  @Inject()
  UserService: UserService;

  @Config('middleware.auth')
  authConfig: any;

  resolve() {
    return async (ctx: Context, next: NextFunction) => {

      const routeInfo = await this.webRouterService.getMatchedRouterInfo(ctx.path, ctx.method);
      // 过滤掉不需要鉴权的接口
      if (
        this.notAuthRouters.some(
          o =>
            o.requestMethod === routeInfo.requestMethod &&
            o.url === routeInfo.url
        )
      ) {
        await next();
        return;
      }

      const _url = ctx.request.url;
      const _unionId = ctx.unionId;
      if (!_unionId) throw new httpError.UnauthorizedError('unionId缺失');

      // 根据unionId查询当前用户信息
      const res = await this.UserService.getUserByUnionIdAndRole(_unionId);
      if (res.success && res.userInfo) {
        if (res.userInfo.user_status) {
          ctx.userInfo = res.userInfo;
          //  当前接口是否需要校验管理员权限
          if (_url.indexOf("/api/v1/admin/") != -1) {
            // ########  当前接口需要校验管理员权限
            if (res.userInfo.role_code && ["admin","manager"].includes(res.userInfo.role_code)) {
              await next();
            } else {
              throw new httpError.UnauthorizedError('用户无权访问');
            }
          } else {
            // ########  当前接口不需要校验管理员权限
            await next();
          }
        } else {
          throw new httpError.UnauthorizedError('用户已禁用，请联系管理员');
        }
      } else {
        throw new httpError.UnauthorizedError('未知用户信息');
      }
    };
  }

  public match(ctx: Context): boolean {
    const { path } = ctx;
    const { prefix } = this.authConfig;
    // const exist = ignore.find((item: any) => {
    //   return item.match(path);
    // });
    return path.indexOf(prefix) === 0;
  }

  public static getName(): string {
    return 'Auth';
  }
}
